package com.imooc.zhousc.controller;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
public class RedisController {

    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping("redisLock")
    public String redisLock(){
        log.info("我进入了方法");
        String key = "redisKey";
        String value = UUID.randomUUID().toString();
        RedisCallback<Boolean> redisCallback = redisConnection -> {
            byte[] serializeKey = redisTemplate.getKeySerializer().serialize(key);
            byte[] serializeVal = redisTemplate.getValueSerializer().serialize(value);
            Expiration seconds = Expiration.seconds(30);
            RedisStringCommands.SetOption nx = RedisStringCommands.SetOption.ifAbsent();
            Boolean set = redisConnection.set(serializeKey, serializeVal, seconds, nx);
            return set;
        };
        // 获取分布式锁
        Boolean locked = (Boolean) redisTemplate.execute(redisCallback);
        if(locked){
            log.info("我进入了锁");
            try {
                Thread.sleep(15000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                // 释放锁
                String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1] then\n" +
                        "    return redis.call(\"del\",KEYS[1])\n" +
                        "else\n" +
                        "    return 0\n" +
                        "end";
                RedisScript<Boolean> redisScript = RedisScript.of(script,Boolean.class);
                List<String> keys = new ArrayList<>();
                keys.add(key);
                Boolean execute = (Boolean) redisTemplate.execute(redisScript, keys, value);
                log.info("释放锁的结果");
            }
        }
        return "方法执行完成";
    }

    @Autowired
    private RedissonClient redissonClient;

    @GetMapping("redissonLock")
    public String redissonLock(){
        RLock lock = redissonClient.getLock("order");
        log.info("我进入了方法");
        try {
            lock.lock(30, TimeUnit.SECONDS);
            log.info("我获得了锁");
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            log.info("我释放了锁");
            lock.unlock();
        }
        log.info("方法执行完成");
        return "OK";
    }
}
